﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Drawing;
using System.Text.RegularExpressions;
using Vit.Common.Extensions;

namespace Vit.Report.XmlWebReport
{
    public class ReportHelper
    {
        public static SizeF GetFontSize(Font font, string text, double lineHeight)
        {
            Bitmap bmp = new Bitmap(1,1);
            Graphics g = Graphics.FromImage(bmp);
            g.PageUnit = font.Unit;
            text = Regex.Replace(text, @"<br\s*/?>", Environment.NewLine);
            SizeF s = g.MeasureString(text, font, 0, StringFormat.GenericTypographic);
            g.Dispose();
            bmp.Dispose();
            s.Width += (float)2;
            s.Height *= (float)lineHeight;
            return s;
        }

        public static SizeF GetFontSize(Font font, double lineHeight)
        {
            return GetFontSize(font, "馨", lineHeight);
        }

        public static int AppendWithContent(Font font, Page page, RectanglePosition rect, PositionType positionType, ref string text, out string split)
        {
            int yOffset = 0;
            split = string.Empty;
            text = text.Trim();
            SizeF textSize = GetFontSize(font, text, rect.LineHeight);
            SizeF fontSize = new SizeF(font.Size, font.Size * (float)rect.LineHeight); //GetFontSize(font, rect.LineHeight);

            int bottom = rect.BottomIndex;
            char right = rect.RightIndex;
            if (rect.RightIndex > page.ContentRectanglePosition.RightIndex)
                right = page.ContentRectanglePosition.RightIndex;
            if (rect.BottomIndex > page.ContentRectanglePosition.BottomIndex)
                bottom = page.ContentRectanglePosition.BottomIndex;
            RectangleF rt = GetRectangle(page, new RectanglePosition(rect.TopLeftPosition, string.Format("{0}{1}", right, bottom)));

            if (textSize.Width > rt.Width)
            {
                int txtYSpan = 0;
                int charIndex = 0;
                int lastIndex = 0;
                List<int> breaks = new List<int>();
                while (charIndex < text.Length)
                {
                    SizeF stextSize = GetFontSize(font, text.Substring(lastIndex, charIndex - lastIndex + 1), rect.LineHeight);
                    if (stextSize.Width <= rt.Width) // && textSize.Height <= rt.Height)
                    {
                        charIndex++;
                    }
                    else
                    {
                        lastIndex = charIndex;
                        breaks.Add(charIndex);
                        charIndex++;
                        txtYSpan++;
                    }
                }

                int count = 0;
                foreach (int b in breaks)
                {
                    text = text.Insert(b + count * 5, "<br/>");
                    count++;
                }

                textSize.Height += txtYSpan * fontSize.Height;
            }
            if (textSize.Height > rt.Height)
            {
                text = text.Replace(Environment.NewLine, "<br/>");
                List<int> breaks = new List<int>();
                int charIndex = text.IndexOf("<br/>");
                while (charIndex >= 0 && charIndex < text.Length)
                {
                    breaks.Add(charIndex);
                    charIndex = text.IndexOf("<br/>", charIndex + 5);
                }

                if (positionType == PositionType.RuntimeCalculationSource)
                {
                    float oldHeight = rt.Height;
                    float pageSpareHeight = page.ContentSize.Height + page.ContentTopLeft.Y - rt.Top;
                    if (textSize.Height < pageSpareHeight)
                        rt.Height = textSize.Height;
                    else
                        rt.Height = pageSpareHeight;

                    int contentOffset = (int)Math.Ceiling((rt.Height - oldHeight) / page.CellSize.Height) + rect.YSpan;
                    rect.AppendTo(0, contentOffset);
                    yOffset += contentOffset;
                    if (rect.BottomIndex <= page.ContentRectanglePosition.BottomIndex)
                    {
                        rt = GetRectangle(page, rect);
                    }
                    else
                    {
                        yOffset += rect.BottomIndex - page.ContentRectanglePosition.BottomIndex;
                    }
                }

                int maxLines = (int)Math.Floor(rt.Height / fontSize.Height) - 1;

                if (maxLines > 0 && breaks.Count > 0 && breaks.Count > maxLines)
                {
                    split = text.Substring(breaks[maxLines]);
                    if (split.StartsWith("<br/>"))
                        split = split.Substring(5);
                    text = text.Substring(0, breaks[maxLines]);
                    int txtOffset = (int)Math.Ceiling((decimal)(breaks.Count - maxLines) / (decimal)(page.CellSize.Height / fontSize.Height));
                    if (txtOffset > 0)
                    {
                        if (positionType != PositionType.RuntimeGeneration)
                        {
                            rect.AppendTo(0, txtOffset);
                            yOffset += txtOffset;
                        }
                    }
                }
            }

            return yOffset;
        }

        public static RectangleF GetRectangle(Page page, RectanglePosition rect)
        {
            RectangleF tl = page.GetCellRectangle(rect.TopLeftPosition);
            RectangleF br = page.GetCellRectangle(rect.BottomRightPosition);

            return new RectangleF(tl.X, tl.Y, br.Right - tl.Left, br.Bottom - tl.Top);
        }

        public static string ToHtmlFont(Font font)
        {
            if (font == null)
                return string.Empty;
            return string.Format("font:{0} {1}mm {2};", font.Style == FontStyle.Bold ? "bold" : "normal", font.Size, font.FontFamily.Name);
        }

        public static Font ParseFont(string font)
        {
            if (string.IsNullOrEmpty(font))
                return null;
            string[] vals = font.Split(new char[] {' '}, StringSplitOptions.RemoveEmptyEntries);

            FontStyle fs = FontStyle.Regular;

            if (vals.Length > 2)
                fs = (FontStyle)Enum.Parse(typeof(FontStyle), vals[2]);

            return new Font(vals[0], float.Parse(vals[1]), fs, GraphicsUnit.Millimeter);
        }

        public static void ParseLocation(string loc, out string topLeftPosition, out string bottomRightPosition)
        {
            if (string.IsNullOrEmpty(loc) || loc.IndexOf(":") <= 0)
                throw new Exception(string.Format("{0} 位置信息不正确", loc));

            string[] vals = loc.Split(new char[] { ':' }, StringSplitOptions.RemoveEmptyEntries);
            topLeftPosition = vals[0];
            bottomRightPosition = vals[1];
        }

        public static void ParseData(string data, out string mapName, out string propName)
        {
            mapName = null;
            propName = null;
            if (string.IsNullOrEmpty(data))
                return;

            string[] vals = data.Split(new char[] { '.' }, StringSplitOptions.RemoveEmptyEntries);
            mapName = vals[0];
            if (vals.Length > 1)
                propName = vals[1];
        }

        public static Margin ParseMargin(string margin)
        {
            if (string.IsNullOrEmpty(margin))
                return new Margin { Top = 0, Left = 0, Bottom = 0, Right = 0 };

            string[] vals = margin.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
            return new Margin
            {
                Top = float.Parse(vals[0]),
                Right = float.Parse(vals[1]),
                Bottom = float.Parse(vals[2]),
                Left = float.Parse(vals[3])
            };
        }

        public static PointF ParsePoint(string point)
        {
            if (string.IsNullOrEmpty(point))
                return new PointF { X = 0, Y = 0 };

            string[] vals = point.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
            return new PointF
            {
                X = float.Parse(vals[0]),
                Y = float.Parse(vals[1])
            };
        }

        public static SizeF ParseSize(string size)
        {
            if (string.IsNullOrEmpty(size))
                return new SizeF { Width = 0, Height = 0 };

            string[] vals = size.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
            return new SizeF
            {
                Width = float.Parse(vals[0]),
                Height = float.Parse(vals[1])
            };
        }

        public static void TranslateCellIndex(string position, out char x, out int y)
        {
            x = 'A';
            y = 0;
            if (!string.IsNullOrEmpty(position))
            {
                foreach (char c in position)
                {
                    if (c >= 'A' && c <= 'Z')
                        x = c;
                    else if (c >= '0' && c <= '9')
                        y = y * 10 + Convert.ToInt32(c.ToString());
                    else
                        throw new Exception("不认识的位置信息");
                }
            }
        }

        public static string ReplaceTokens(Page page, string content)
        {
            if (!string.IsNullOrEmpty(content) && content.IndexOf("{") >= 0 && content.IndexOf("}") > 0)
            {
                Dictionary<string, string> words = new Dictionary<string, string>();
                words.Add("{TOTALPAGES}", page.Report.PageCount.ToString());
                words.Add("{PAGEINDEX}", (page.PageIndex + 1).ToString());

                return content.Replace(words);
            }
            return content;
        }

        public static string TrimHtml(string html)
        {
            if (string.IsNullOrEmpty(html))
                return html;
            html = Regex.Replace(html, @"<br\s*/?>", Environment.NewLine);
            html = Regex.Replace(html, @"<p\s*/?>", Environment.NewLine);
            html = Regex.Replace(html, "<[^>]*>", string.Empty);
            html = html.Replace("&nbsp;", " ");
            return html.Trim();
        }

        public static string ResolveToHtml(string plainText)
        {
            plainText = plainText.Replace(Environment.NewLine, "<br/>");
            //plainText = plainText.Replace(" ", "&bnsp;");
            return plainText;
        }
    }
}
